diff --git a/noti/Noti_InstallIndicator.php b/noti/Noti_InstallIndicator.php new file mode 100644 index 0000000..d9310ba --- /dev/null +++ b/noti/Noti_InstallIndicator.php @@ -0,0 +1,185 @@ +getOption(self::optionInstalled) == true; + } + + /** + * Note in DB that the plugin is installed + * @return null + */ + protected function markAsInstalled() { + return $this->updateOption(self::optionInstalled, true); + } + + /** + * Note in DB that the plugin is uninstalled + * @return bool returned form delete_option. + * true implies the plugin was installed at the time of this call, + * false implies it was not. + */ + protected function markAsUnInstalled() { + return $this->deleteOption(self::optionInstalled); + } + + /** + * Set a version string in the options. This is useful if you install upgrade and + * need to check if an older version was installed to see if you need to do certain + * upgrade housekeeping (e.g. changes to DB schema). + * @return null + */ + protected function getVersionSaved() { + return $this->getOption(self::optionVersion); + } + + /** + * Set a version string in the options. + * need to check if + * @param $version string best practice: use a dot-delimited string like '1.2.3' so version strings can be easily + * compared using version_compare (http://php.net/manual/en/function.version-compare.php) + * @return null + */ + protected function setVersionSaved($version) { + return $this->updateOption(self::optionVersion, $version); + } + + /** + * @return string name of the main plugin file that has the header section with + * "Plugin Name", "Version", "Description", "Text Domain", etc. + */ + protected function getMainPluginFileName() { + return basename(dirname(__FILE__)) . 'php'; + } + + /** + * Get a value for input key in the header section of main plugin file. + * E.g. "Plugin Name", "Version", "Description", "Text Domain", etc. + * @param $key string plugin header key + * @return string if found, otherwise null + */ + public function getPluginHeaderValue($key) { + // Read the string from the comment header of the main plugin file + $data = file_get_contents($this->getPluginDir() . DIRECTORY_SEPARATOR . $this->getMainPluginFileName()); + $match = array(); + preg_match('/' . $key . ':\s*(\S+)/', $data, $match); + if (count($match) >= 1) { + return $match[1]; + } + return null; + } + + /** + * If your subclass of this class lives in a different directory, + * override this method with the exact same code. Since __FILE__ will + * be different, you will then get the right dir returned. + * @return string + */ + protected function getPluginDir() { + return dirname(__FILE__); + } + + /** + * Version of this code. + * Best practice: define version strings to be easily compared using version_compare() + * (http://php.net/manual/en/function.version-compare.php) + * NOTE: You should manually make this match the SVN tag for your main plugin file 'Version' release and 'Stable tag' in readme.txt + * @return string + */ + public function getVersion() { + return $this->getPluginHeaderValue('Version'); + } + + + /** + * Useful when checking for upgrades, can tell if the currently installed version is earlier than the + * newly installed code. This case indicates that an upgrade has been installed and this is the first time it + * has been activated, so any upgrade actions should be taken. + * @return bool true if the version saved in the options is earlier than the version declared in getVersion(). + * true indicates that new code is installed and this is the first time it is activated, so upgrade actions + * should be taken. Assumes that version string comparable by version_compare, examples: '1', '1.1', '1.1.1', '2.0', etc. + */ + public function isInstalledCodeAnUpgrade() { + return $this->isSavedVersionLessThan($this->getVersion()); + } + + /** + * Used to see if the installed code is an earlier version than the input version + * @param $aVersion string + * @return bool true if the saved version is earlier (by natural order) than the input version + */ + public function isSavedVersionLessThan($aVersion) { + return $this->isVersionLessThan($this->getVersionSaved(), $aVersion); + } + + /** + * Used to see if the installed code is the same or earlier than the input version. + * Useful when checking for an upgrade. If you haven't specified the number of the newer version yet, + * but the last version (installed) was 2.3 (for example) you could check if + * For example, $this->isSavedVersionLessThanEqual('2.3') == true indicates that the saved version is not upgraded + * past 2.3 yet and therefore you would perform some appropriate upgrade action. + * @param $aVersion string + * @return bool true if the saved version is earlier (by natural order) than the input version + */ + public function isSavedVersionLessThanEqual($aVersion) { + return $this->isVersionLessThanEqual($this->getVersionSaved(), $aVersion); + } + + /** + * @param $version1 string a version string such as '1', '1.1', '1.1.1', '2.0', etc. + * @param $version2 string a version string such as '1', '1.1', '1.1.1', '2.0', etc. + * @return bool true if version_compare of $versions1 and $version2 shows $version1 as the same or earlier + */ + public function isVersionLessThanEqual($version1, $version2) { + return (version_compare($version1, $version2) <= 0); + } + + /** + * @param $version1 string a version string such as '1', '1.1', '1.1.1', '2.0', etc. + * @param $version2 string a version string such as '1', '1.1', '1.1.1', '2.0', etc. + * @return bool true if version_compare of $versions1 and $version2 shows $version1 as earlier + */ + public function isVersionLessThan($version1, $version2) { + return (version_compare($version1, $version2) < 0); + } + + /** + * Record the installed version to options. + * This helps track was version is installed so when an upgrade is installed, it should call this when finished + * upgrading to record the new current version + * @return void + */ + protected function saveInstalledVersion() { + $this->setVersionSaved($this->getVersion()); + } + + +} diff --git a/noti/Noti_LifeCycle.php b/noti/Noti_LifeCycle.php new file mode 100644 index 0000000..b577f01 --- /dev/null +++ b/noti/Noti_LifeCycle.php @@ -0,0 +1,197 @@ +initOptions(); + + // Initialize DB Tables used by the plugin + $this->installDatabaseTables(); + + // Other Plugin initialization - for the plugin writer to override as needed + $this->otherInstall(); + + // Record the installed version + $this->saveInstalledVersion(); + + // To avoid running install() more then once + $this->markAsInstalled(); + } + + public function uninstall() { + $this->otherUninstall(); + $this->unInstallDatabaseTables(); + $this->deleteSavedOptions(); + $this->markAsUnInstalled(); + } + + /** + * Perform any version-upgrade activities prior to activation (e.g. database changes) + * @return void + */ + public function upgrade() { + } + + /** + * See: http://plugin.michael-simpson.com/?page_id=105 + * @return void + */ + public function activate() { + } + + /** + * See: http://plugin.michael-simpson.com/?page_id=105 + * @return void + */ + public function deactivate() { + } + + /** + * See: http://plugin.michael-simpson.com/?page_id=31 + * @return void + */ + protected function initOptions() { + } + + public function addActionsAndFilters() { + } + + /** + * See: http://plugin.michael-simpson.com/?page_id=101 + * Called by install() to create any database tables if needed. + * Best Practice: + * (1) Prefix all table names with $wpdb->prefix + * (2) make table names lower case only + * @return void + */ + protected function installDatabaseTables() { + } + + /** + * See: http://plugin.michael-simpson.com/?page_id=101 + * Drop plugin-created tables on uninstall. + * @return void + */ + protected function unInstallDatabaseTables() { + } + + /** + * Override to add any additional actions to be done at install time + * See: http://plugin.michael-simpson.com/?page_id=33 + * @return void + */ + protected function otherInstall() { + } + + /** + * Override to add any additional actions to be done at uninstall time + * See: http://plugin.michael-simpson.com/?page_id=33 + * @return void + */ + protected function otherUninstall() { + } + + /** + * Puts the configuration page in the Plugins menu by default. + * Override to put it elsewhere or create a set of submenus + * Override with an empty implementation if you don't want a configuration page + * @return void + */ + public function addSettingsSubMenuPage() { + $this->addSettingsSubMenuPageToPluginsMenu(); + //$this->addSettingsSubMenuPageToSettingsMenu(); + } + + + protected function requireExtraPluginFiles() { + require_once(ABSPATH . 'wp-includes/pluggable.php'); + require_once(ABSPATH . 'wp-admin/includes/plugin.php'); + } + + /** + * @return string Slug name for the URL to the Setting page + * (i.e. the page for setting options) + */ + protected function getSettingsSlug() { + return get_class($this) . 'Settings'; + } + + protected function addSettingsSubMenuPageToPluginsMenu() { + $this->requireExtraPluginFiles(); + $displayName = $this->getPluginDisplayName(); + add_submenu_page('plugins.php', + $displayName, + $displayName, + 'manage_options', + $this->getSettingsSlug(), + array(&$this, 'settingsPage')); + } + + + protected function addSettingsSubMenuPageToSettingsMenu() { + $this->requireExtraPluginFiles(); + $displayName = $this->getPluginDisplayName(); + add_options_page($displayName, + $displayName, + 'manage_options', + $this->getSettingsSlug(), + array(&$this, 'settingsPage')); + } + + /** + * @param $name string name of a database table + * @return string input prefixed with the WordPress DB table prefix + * plus the prefix for this plugin (lower-cased) to avoid table name collisions. + * The plugin prefix is lower-cases as a best practice that all DB table names are lower case to + * avoid issues on some platforms + */ + protected function prefixTableName($name) { + global $wpdb; + return $wpdb->prefix . strtolower($this->prefix($name)); + } + + + /** + * Convenience function for creating AJAX URLs. + * + * @param $actionName string the name of the ajax action registered in a call like + * add_action('wp_ajax_actionName', array(&$this, 'functionName')); + * and/or + * add_action('wp_ajax_nopriv_actionName', array(&$this, 'functionName')); + * + * If have an additional parameters to add to the Ajax call, e.g. an "id" parameter, + * you could call this function and append to the returned string like: + * $url = $this->getAjaxUrl('myaction&id=') . urlencode($id); + * or more complex: + * $url = sprintf($this->getAjaxUrl('myaction&id=%s&var2=%s&var3=%s'), urlencode($id), urlencode($var2), urlencode($var3)); + * + * @return string URL that can be used in a web page to make an Ajax call to $this->functionName + */ + public function getAjaxUrl($actionName) { + return admin_url('admin-ajax.php') . '?action=' . $actionName; + } + +} diff --git a/noti/Noti_OptionsManager.php b/noti/Noti_OptionsManager.php new file mode 100644 index 0000000..1fe08aa --- /dev/null +++ b/noti/Noti_OptionsManager.php @@ -0,0 +1,461 @@ +display-name and/or key=>array(display-name, choice1, choice2, ...) + * key: an option name for the key (this name will be given a prefix when stored in + * the database to ensure it does not conflict with other plugin options) + * value: can be one of two things: + * (1) string display name for displaying the name of the option to the user on a web page + * (2) array where the first element is a display name (as above) and the rest of + * the elements are choices of values that the user can select + * e.g. + * array( + * 'item' => 'Item:', // key => display-name + * 'rating' => array( // key => array ( display-name, choice1, choice2, ...) + * 'CanDoOperationX' => array('Can do Operation X', 'Administrator', 'Editor', 'Author', 'Contributor', 'Subscriber'), + * 'Rating:', 'Excellent', 'Good', 'Fair', 'Poor') + */ + public function getOptionMetaData() { + return array(); + } + + /** + * @return array of string name of options + */ + public function getOptionNames() { + return array_keys($this->getOptionMetaData()); + } + + /** + * Override this method to initialize options to default values and save to the database with add_option + * @return void + */ + protected function initOptions() { + } + + /** + * Cleanup: remove all options from the DB + * @return void + */ + protected function deleteSavedOptions() { + $optionMetaData = $this->getOptionMetaData(); + if (is_array($optionMetaData)) { + foreach ($optionMetaData as $aOptionKey => $aOptionMeta) { + $prefixedOptionName = $this->prefix($aOptionKey); // how it is stored in DB + delete_option($prefixedOptionName); + } + } + } + + /** + * @return string display name of the plugin to show as a name/title in HTML. + * Just returns the class name. Override this method to return something more readable + */ + public function getPluginDisplayName() { + return get_class($this); + } + + /** + * Get the prefixed version input $name suitable for storing in WP options + * Idempotent: if $optionName is already prefixed, it is not prefixed again, it is returned without change + * @param $name string option name to prefix. Defined in settings.php and set as keys of $this->optionMetaData + * @return string + */ + public function prefix($name) { + $optionNamePrefix = $this->getOptionNamePrefix(); + if (strpos($name, $optionNamePrefix) === 0) { // 0 but not false + return $name; // already prefixed + } + return $optionNamePrefix . $name; + } + + /** + * Remove the prefix from the input $name. + * Idempotent: If no prefix found, just returns what was input. + * @param $name string + * @return string $optionName without the prefix. + */ + public function &unPrefix($name) { + $optionNamePrefix = $this->getOptionNamePrefix(); + if (strpos($name, $optionNamePrefix) === 0) { + return substr($name, strlen($optionNamePrefix)); + } + return $name; + } + + /** + * A wrapper function delegating to WP get_option() but it prefixes the input $optionName + * to enforce "scoping" the options in the WP options table thereby avoiding name conflicts + * @param $optionName string defined in settings.php and set as keys of $this->optionMetaData + * @param $default string default value to return if the option is not set + * @return string the value from delegated call to get_option(), or optional default value + * if option is not set. + */ + public function getOption($optionName, $default = null) { + $prefixedOptionName = $this->prefix($optionName); // how it is stored in DB + $retVal = get_option($prefixedOptionName); + if (!$retVal && $default) { + $retVal = $default; + } + return $retVal; + } + + /** + * A wrapper function delegating to WP delete_option() but it prefixes the input $optionName + * to enforce "scoping" the options in the WP options table thereby avoiding name conflicts + * @param $optionName string defined in settings.php and set as keys of $this->optionMetaData + * @return bool from delegated call to delete_option() + */ + public function deleteOption($optionName) { + $prefixedOptionName = $this->prefix($optionName); // how it is stored in DB + return delete_option($prefixedOptionName); + } + + /** + * A wrapper function delegating to WP add_option() but it prefixes the input $optionName + * to enforce "scoping" the options in the WP options table thereby avoiding name conflicts + * @param $optionName string defined in settings.php and set as keys of $this->optionMetaData + * @param $value mixed the new value + * @return null from delegated call to delete_option() + */ + public function addOption($optionName, $value) { + $prefixedOptionName = $this->prefix($optionName); // how it is stored in DB + return add_option($prefixedOptionName, $value); + } + + /** + * A wrapper function delegating to WP add_option() but it prefixes the input $optionName + * to enforce "scoping" the options in the WP options table thereby avoiding name conflicts + * @param $optionName string defined in settings.php and set as keys of $this->optionMetaData + * @param $value mixed the new value + * @return null from delegated call to delete_option() + */ + public function updateOption($optionName, $value) { + $prefixedOptionName = $this->prefix($optionName); // how it is stored in DB + return update_option($prefixedOptionName, $value); + } + + /** + * A Role Option is an option defined in getOptionMetaData() as a choice of WP standard roles, e.g. + * 'CanDoOperationX' => array('Can do Operation X', 'Administrator', 'Editor', 'Author', 'Contributor', 'Subscriber') + * The idea is use an option to indicate what role level a user must minimally have in order to do some operation. + * So if a Role Option 'CanDoOperationX' is set to 'Editor' then users which role 'Editor' or above should be + * able to do Operation X. + * Also see: canUserDoRoleOption() + * @param $optionName + * @return string role name + */ + public function getRoleOption($optionName) { + $roleAllowed = $this->getOption($optionName); + if (!$roleAllowed || $roleAllowed == '') { + $roleAllowed = 'Administrator'; + } + return $roleAllowed; + } + + /** + * Given a WP role name, return a WP capability which only that role and roles above it have + * http://codex.wordpress.org/Roles_and_Capabilities + * @param $roleName + * @return string a WP capability or '' if unknown input role + */ + protected function roleToCapability($roleName) { + switch ($roleName) { + case 'Super Admin': + return 'manage_options'; + case 'Administrator': + return 'manage_options'; + case 'Editor': + return 'publish_pages'; + case 'Author': + return 'publish_posts'; + case 'Contributor': + return 'edit_posts'; + case 'Subscriber': + return 'read'; + case 'Anyone': + return 'read'; + } + return ''; + } + + /** + * @param $roleName string a standard WP role name like 'Administrator' + * @return bool + */ + public function isUserRoleEqualOrBetterThan($roleName) { + if ('Anyone' == $roleName) { + return true; + } + $capability = $this->roleToCapability($roleName); + return current_user_can($capability); + } + + /** + * @param $optionName string name of a Role option (see comments in getRoleOption()) + * @return bool indicates if the user has adequate permissions + */ + public function canUserDoRoleOption($optionName) { + $roleAllowed = $this->getRoleOption($optionName); + if ('Anyone' == $roleAllowed) { + return true; + } + return $this->isUserRoleEqualOrBetterThan($roleAllowed); + } + + /** + * see: http://codex.wordpress.org/Creating_Options_Pages + * @return void + */ + public function createSettingsMenu() { + $pluginName = $this->getPluginDisplayName(); + //create new top-level menu + add_menu_page($pluginName . ' Plugin Settings', + $pluginName, + 'administrator', + get_class($this), + array(&$this, 'settingsPage') + /*,plugins_url('/images/icon.png', __FILE__)*/); // if you call 'plugins_url; be sure to "require_once" it + + //call register settings function + add_action('admin_init', array(&$this, 'registerSettings')); + } + + public function registerSettings() { + $settingsGroup = get_class($this) . '-settings-group'; + $optionMetaData = $this->getOptionMetaData(); + foreach ($optionMetaData as $aOptionKey => $aOptionMeta) { + register_setting($settingsGroup, $aOptionMeta); + } + } + + /** + * Creates HTML for the Administration page to set options for this plugin. + * Override this method to create a customized page. + * @return void + */ + public function settingsPage() { + if (!current_user_can('manage_options')) { + wp_die(__('You do not have sufficient permissions to access this page.', 'noti')); + } + + $optionMetaData = $this->getOptionMetaData(); + + // Save Posted Options + if ($optionMetaData != null) { + foreach ($optionMetaData as $optionMetaDataSingle) { + if (isset($_POST[$optionMetaDataSingle['key']])) { + $this->updateOption($optionMetaDataSingle['key'], $_POST[$optionMetaDataSingle['key']]); + } + } + } + + // HTML for the page + $settingsGroup = get_class($this) . '-settings-group'; + ?> +
| + | ++ + | ++ |
| + | + + + | ++ |
The event was added to your calendar. Check out all your events in your event overview.
', + 'flip' : 'Your preferences have been saved successfully. See all your settings in your profile overview.
', + 'exploader' : 'Your preferences have been saved successfully. See all your settings in your profile overview.
', + 'slidetop' : 'You have some interesting news in your inbox. Go check it out now.
', + 'genie' : 'Your preferences have been saved successfully. See all your settings in your profile overview.
', + 'jelly' : 'Hello there! I\'m a classic notification but I have some elastic jelliness thanks to bounce.js.
', + 'slide' : 'This notification has slight elasticity to it thanks to bounce.js.
', + 'scale' : 'This is just a simple notice. Everything is in order and this is a simple link.
', + 'boxspinner' : 'I am using a beautiful spinner from SpinKit
', + 'cornerexpand' : 'I\'m appaering in a morphed shape thanks to Snap.svg
', + 'loadingcircle' : 'Whatever you did, it was successful!
', + 'thumbslider' : '
Zoe Moulder accepted your invitation.
Q(e,g)||Q(b,d)
Q(f,h))){var i=(a*d-b*c)*(e-g)-(a-c)*(e*h-f*g),j=(a*d-b*c)*(f-h)-(b-d)*(e*h-f*g),k=(a-c)*(f-h)-(b-d)*(e-g);if(k){var l=i/k,m=j/k,n=+l.toFixed(2),o=+m.toFixed(2);if(!(n<+P(a,c).toFixed(2)||n>+Q(a,c).toFixed(2)||n<+P(e,g).toFixed(2)||n>+Q(e,g).toFixed(2)||o<+P(b,d).toFixed(2)||o>+Q(b,d).toFixed(2)||o<+P(f,h).toFixed(2)||o>+Q(f,h).toFixed(2)))return{x:l,y:m}}}}function q(a,b,c){var d=j(a),e=j(b);if(!l(d,e))return c?0:[];for(var f=n.apply(0,a),g=n.apply(0,b),h=~~(f/8),k=~~(g/8),m=[],o=[],q={},r=c?0:[],s=0;h+1>s;s++){var t=i.apply(0,a.concat(s/h));m.push({x:t.x,y:t.y,t:s/h})}for(s=0;k+1>s;s++)t=i.apply(0,b.concat(s/k)),o.push({x:t.x,y:t.y,t:s/k});for(s=0;h>s;s++)for(var u=0;k>u;u++){var v=m[s],w=m[s+1],x=o[u],y=o[u+1],z=S(w.x-v.x)<.001?"y":"x",A=S(y.x-x.x)<.001?"y":"x",B=p(v.x,v.y,w.x,w.y,x.x,x.y,y.x,y.y);if(B){if(q[B.x.toFixed(4)]==B.y.toFixed(4))continue;q[B.x.toFixed(4)]=B.y.toFixed(4);var C=v.t+S((B[z]-v[z])/(w[z]-v[z]))*(w.t-v.t),D=x.t+S((B[A]-x[A])/(y[A]-x[A]))*(y.t-x.t);C>=0&&1>=C&&D>=0&&1>=D&&(c?r++:r.push({x:B.x,y:B.y,t1:C,t2:D}))}}return r}function r(a,b){return t(a,b)}function s(a,b){return t(a,b,1)}function t(a,b,c){a=E(a),b=E(b);for(var d,e,f,g,h,i,j,k,l,m,n=c?0:[],o=0,p=a.length;p>o;o++){var r=a[o];if("M"==r[0])d=h=r[1],e=i=r[2];else{"C"==r[0]?(l=[d,e].concat(r.slice(1)),d=l[6],e=l[7]):(l=[d,e,d,e,h,i,h,i],d=h,e=i);for(var s=0,t=b.length;t>s;s++){var u=b[s];if("M"==u[0])f=j=u[1],g=k=u[2];else{"C"==u[0]?(m=[f,g].concat(u.slice(1)),f=m[6],g=m[7]):(m=[f,g,f,g,j,k,j,k],f=j,g=k);var v=q(l,m,c);if(c)n+=v;else{for(var w=0,x=v.length;x>w;w++)v[w].segment1=o,v[w].segment2=s,v[w].bez1=l,v[w].bez2=m;n=n.concat(v)}}}}}return n}function u(a,b,c){var d=v(a);return k(d,b,c)&&t(a,[["M",b,c],["H",d.x2+10]],1)%2==1}function v(a){var b=c(a);if(b.bbox)return J(b.bbox);if(!a)return d();a=E(a);for(var e,f=0,g=0,h=[],i=[],j=0,k=a.length;k>j;j++)if(e=a[j],"M"==e[0])f=e[1],g=e[2],h.push(f),i.push(g);else{var l=D(f,g,e[1],e[2],e[3],e[4],e[5],e[6]);h=h.concat(l.min.x,l.max.x),i=i.concat(l.min.y,l.max.y),f=e[5],g=e[6]}var m=P.apply(0,h),n=P.apply(0,i),o=Q.apply(0,h),p=Q.apply(0,i),q=d(m,n,o-m,p-n);return b.bbox=J(q),q}function w(a,b,c,d,f){if(f)return[["M",+a+ +f,b],["l",c-2*f,0],["a",f,f,0,0,1,f,f],["l",0,d-2*f],["a",f,f,0,0,1,-f,f],["l",2*f-c,0],["a",f,f,0,0,1,-f,-f],["l",0,2*f-d],["a",f,f,0,0,1,f,-f],["z"]];var g=[["M",a,b],["l",c,0],["l",0,d],["l",-c,0],["z"]];return g.toString=e,g}function x(a,b,c,d,f){if(null==f&&null==d&&(d=c),a=+a,b=+b,c=+c,d=+d,null!=f)var g=Math.PI/180,h=a+c*Math.cos(-d*g),i=a+c*Math.cos(-f*g),j=b+c*Math.sin(-d*g),k=b+c*Math.sin(-f*g),l=[["M",h,j],["A",c,c,0,+(f-d>180),0,i,k]];else l=[["M",a,b],["m",0,-d],["a",c,d,0,1,1,0,2*d],["a",c,d,0,1,1,0,-2*d],["z"]];return l.toString=e,l}function y(b){var d=c(b),g=String.prototype.toLowerCase;if(d.rel)return f(d.rel);a.is(b,"array")&&a.is(b&&b[0],"array")||(b=a.parsePathString(b));var h=[],i=0,j=0,k=0,l=0,m=0;"M"==b[0][0]&&(i=b[0][1],j=b[0][2],k=i,l=j,m++,h.push(["M",i,j]));for(var n=m,o=b.length;o>n;n++){var p=h[n]=[],q=b[n];if(q[0]!=g.call(q[0]))switch(p[0]=g.call(q[0]),p[0]){case"a":p[1]=q[1],p[2]=q[2],p[3]=q[3],p[4]=q[4],p[5]=q[5],p[6]=+(q[6]-i).toFixed(3),p[7]=+(q[7]-j).toFixed(3);break;case"v":p[1]=+(q[1]-j).toFixed(3);break;case"m":k=q[1],l=q[2];default:for(var r=1,s=q.length;s>r;r++)p[r]=+(q[r]-(r%2?i:j)).toFixed(3)}else{p=h[n]=[],"m"==q[0]&&(k=q[1]+i,l=q[2]+j);for(var t=0,u=q.length;u>t;t++)h[n][t]=q[t]}var v=h[n].length;switch(h[n][0]){case"z":i=k,j=l;break;case"h":i+=+h[n][v-1];break;case"v":j+=+h[n][v-1];break;default:i+=+h[n][v-2],j+=+h[n][v-1]}}return h.toString=e,d.rel=f(h),h}function z(b){var d=c(b);if(d.abs)return f(d.abs);if(I(b,"array")&&I(b&&b[0],"array")||(b=a.parsePathString(b)),!b||!b.length)return[["M",0,0]];var g,h=[],i=0,j=0,k=0,l=0,m=0;"M"==b[0][0]&&(i=+b[0][1],j=+b[0][2],k=i,l=j,m++,h[0]=["M",i,j]);for(var n,o,p=3==b.length&&"M"==b[0][0]&&"R"==b[1][0].toUpperCase()&&"Z"==b[2][0].toUpperCase(),q=m,r=b.length;r>q;q++){if(h.push(n=[]),o=b[q],g=o[0],g!=g.toUpperCase())switch(n[0]=g.toUpperCase(),n[0]){case"A":n[1]=o[1],n[2]=o[2],n[3]=o[3],n[4]=o[4],n[5]=o[5],n[6]=+o[6]+i,n[7]=+o[7]+j;break;case"V":n[1]=+o[1]+j;break;case"H":n[1]=+o[1]+i;break;case"R":for(var s=[i,j].concat(o.slice(1)),t=2,u=s.length;u>t;t++)s[t]=+s[t]+i,s[++t]=+s[t]+j;h.pop(),h=h.concat(G(s,p));break;case"O":h.pop(),s=x(i,j,o[1],o[2]),s.push(s[0]),h=h.concat(s);break;case"U":h.pop(),h=h.concat(x(i,j,o[1],o[2],o[3])),n=["U"].concat(h[h.length-1].slice(-2));break;case"M":k=+o[1]+i,l=+o[2]+j;default:for(t=1,u=o.length;u>t;t++)n[t]=+o[t]+(t%2?i:j)}else if("R"==g)s=[i,j].concat(o.slice(1)),h.pop(),h=h.concat(G(s,p)),n=["R"].concat(o.slice(-2));else if("O"==g)h.pop(),s=x(i,j,o[1],o[2]),s.push(s[0]),h=h.concat(s);else if("U"==g)h.pop(),h=h.concat(x(i,j,o[1],o[2],o[3])),n=["U"].concat(h[h.length-1].slice(-2));else for(var v=0,w=o.length;w>v;v++)n[v]=o[v];if(g=g.toUpperCase(),"O"!=g)switch(n[0]){case"Z":i=+k,j=+l;break;case"H":i=n[1];break;case"V":j=n[1];break;case"M":k=n[n.length-2],l=n[n.length-1];default:i=n[n.length-2],j=n[n.length-1]}}return h.toString=e,d.abs=f(h),h}function A(a,b,c,d){return[a,b,c,d,c,d]}function B(a,b,c,d,e,f){var g=1/3,h=2/3;return[g*a+h*c,g*b+h*d,g*e+h*c,g*f+h*d,e,f]}function C(b,c,d,e,f,g,h,i,j,k){var l,m=120*O/180,n=O/180*(+f||0),o=[],p=a._.cacher(function(a,b,c){var d=a*N.cos(c)-b*N.sin(c),e=a*N.sin(c)+b*N.cos(c);return{x:d,y:e}});if(k)y=k[0],z=k[1],w=k[2],x=k[3];else{l=p(b,c,-n),b=l.x,c=l.y,l=p(i,j,-n),i=l.x,j=l.y;var q=(N.cos(O/180*f),N.sin(O/180*f),(b-i)/2),r=(c-j)/2,s=q*q/(d*d)+r*r/(e*e);s>1&&(s=N.sqrt(s),d=s*d,e=s*e);var t=d*d,u=e*e,v=(g==h?-1:1)*N.sqrt(S((t*u-t*r*r-u*q*q)/(t*r*r+u*q*q))),w=v*d*r/e+(b+i)/2,x=v*-e*q/d+(c+j)/2,y=N.asin(((c-x)/e).toFixed(9)),z=N.asin(((j-x)/e).toFixed(9));y=w>b?O-y:y,z=w>i?O-z:z,0>y&&(y=2*O+y),0>z&&(z=2*O+z),h&&y>z&&(y-=2*O),!h&&z>y&&(z-=2*O)}var A=z-y;if(S(A)>m){var B=z,D=i,E=j;z=y+m*(h&&z>y?1:-1),i=w+d*N.cos(z),j=x+e*N.sin(z),o=C(i,j,d,e,f,0,h,D,E,[z,B,w,x])}A=z-y;var F=N.cos(y),G=N.sin(y),H=N.cos(z),I=N.sin(z),J=N.tan(A/4),K=4/3*d*J,L=4/3*e*J,M=[b,c],P=[b+K*G,c-L*F],Q=[i+K*I,j-L*H],R=[i,j];if(P[0]=2*M[0]-P[0],P[1]=2*M[1]-P[1],k)return[P,Q,R].concat(o);o=[P,Q,R].concat(o).join().split(",");for(var T=[],U=0,V=o.length;V>U;U++)T[U]=U%2?p(o[U-1],o[U],n).y:p(o[U],o[U+1],n).x;return T}function D(a,b,c,d,e,f,g,h){for(var i,j,k,l,m,n,o,p,q=[],r=[[],[]],s=0;2>s;++s)if(0==s?(j=6*a-12*c+6*e,i=-3*a+9*c-9*e+3*g,k=3*c-3*a):(j=6*b-12*d+6*f,i=-3*b+9*d-9*f+3*h,k=3*d-3*b),S(i)<1e-12){if(S(j)<1e-12)continue;l=-k/j,l>0&&1>l&&q.push(l)}else o=j*j-4*k*i,p=N.sqrt(o),0>o||(m=(-j+p)/(2*i),m>0&&1>m&&q.push(m),n=(-j-p)/(2*i),n>0&&1>n&&q.push(n));for(var t,u=q.length,v=u;u--;)l=q[u],t=1-l,r[0][u]=t*t*t*a+3*t*t*l*c+3*t*l*l*e+l*l*l*g,r[1][u]=t*t*t*b+3*t*t*l*d+3*t*l*l*f+l*l*l*h;return r[0][v]=a,r[1][v]=b,r[0][v+1]=g,r[1][v+1]=h,r[0].length=r[1].length=v+2,{min:{x:P.apply(0,r[0]),y:P.apply(0,r[1])},max:{x:Q.apply(0,r[0]),y:Q.apply(0,r[1])}}}function E(a,b){var d=!b&&c(a);if(!b&&d.curve)return f(d.curve);for(var e=z(a),g=b&&z(b),h={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},i={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},j=(function(a,b,c){var d,e;if(!a)return["C",b.x,b.y,b.x,b.y,b.x,b.y];switch(!(a[0]in{T:1,Q:1})&&(b.qx=b.qy=null),a[0]){case"M":b.X=a[1],b.Y=a[2];break;case"A":a=["C"].concat(C.apply(0,[b.x,b.y].concat(a.slice(1))));break;case"S":"C"==c||"S"==c?(d=2*b.x-b.bx,e=2*b.y-b.by):(d=b.x,e=b.y),a=["C",d,e].concat(a.slice(1));break;case"T":"Q"==c||"T"==c?(b.qx=2*b.x-b.qx,b.qy=2*b.y-b.qy):(b.qx=b.x,b.qy=b.y),a=["C"].concat(B(b.x,b.y,b.qx,b.qy,a[1],a[2]));break;case"Q":b.qx=a[1],b.qy=a[2],a=["C"].concat(B(b.x,b.y,a[1],a[2],a[3],a[4]));break;case"L":a=["C"].concat(A(b.x,b.y,a[1],a[2]));break;case"H":a=["C"].concat(A(b.x,b.y,a[1],b.y));break;case"V":a=["C"].concat(A(b.x,b.y,b.x,a[1]));break;case"Z":a=["C"].concat(A(b.x,b.y,b.X,b.Y))}return a}),k=function(a,b){if(a[b].length>7){a[b].shift();for(var c=a[b];c.length;)m[b]="A",g&&(n[b]="A"),a.splice(b++,0,["C"].concat(c.splice(0,6)));a.splice(b,1),r=Q(e.length,g&&g.length||0)}},l=function(a,b,c,d,f){a&&b&&"M"==a[f][0]&&"M"!=b[f][0]&&(b.splice(f,0,["M",d.x,d.y]),c.bx=0,c.by=0,c.x=a[f][1],c.y=a[f][2],r=Q(e.length,g&&g.length||0))},m=[],n=[],o="",p="",q=0,r=Q(e.length,g&&g.length||0);r>q;q++){e[q]&&(o=e[q][0]),"C"!=o&&(m[q]=o,q&&(p=m[q-1])),e[q]=j(e[q],h,p),"A"!=m[q]&&"C"==o&&(m[q]="C"),k(e,q),g&&(g[q]&&(o=g[q][0]),"C"!=o&&(n[q]=o,q&&(p=n[q-1])),g[q]=j(g[q],i,p),"A"!=n[q]&&"C"==o&&(n[q]="C"),k(g,q)),l(e,g,h,i,q),l(g,e,i,h,q);var s=e[q],t=g&&g[q],u=s.length,v=g&&t.length;h.x=s[u-2],h.y=s[u-1],h.bx=M(s[u-4])||h.x,h.by=M(s[u-3])||h.y,i.bx=g&&(M(t[v-4])||i.x),i.by=g&&(M(t[v-3])||i.y),i.x=g&&t[v-2],i.y=g&&t[v-1]}return g||(d.curve=f(e)),g?[e,g]:e}function F(a,b){if(!b)return a;var c,d,e,f,g,h,i;for(a=E(a),e=0,g=a.length;g>e;e++)for(i=a[e],f=1,h=i.length;h>f;f+=2)c=b.x(i[f],i[f+1]),d=b.y(i[f],i[f+1]),i[f]=c,i[f+1]=d;return a}function G(a,b){for(var c=[],d=0,e=a.length;e-2*!b>d;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4==d?f[3]={x:+a[0],y:+a[1]}:e-2==d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4==d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push(["C",(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}var H=b.prototype,I=a.is,J=a._.clone,K="hasOwnProperty",L=/,?([a-z]),?/gi,M=parseFloat,N=Math,O=N.PI,P=N.min,Q=N.max,R=N.pow,S=N.abs,T=h(1),U=h(),V=h(0,1),W=a._unit2px,X={path:function(a){return a.attr("path")},circle:function(a){var b=W(a);return x(b.cx,b.cy,b.r)},ellipse:function(a){var b=W(a);return x(b.cx||0,b.cy||0,b.rx,b.ry)},rect:function(a){var b=W(a);return w(b.x||0,b.y||0,b.width,b.height,b.rx,b.ry)},image:function(a){var b=W(a);return w(b.x||0,b.y||0,b.width,b.height)},line:function(a){return"M"+[a.attr("x1")||0,a.attr("y1")||0,a.attr("x2"),a.attr("y2")]},polyline:function(a){return"M"+a.attr("points")},polygon:function(a){return"M"+a.attr("points")+"z"},deflt:function(a){var b=a.node.getBBox();return w(b.x,b.y,b.width,b.height)}};a.path=c,a.path.getTotalLength=T,a.path.getPointAtLength=U,a.path.getSubpath=function(a,b,c){if(this.getTotalLength(a)-c<1e-6)return V(a,b).end;var d=V(a,c,1);return b?V(d,b).end:d},H.getTotalLength=function(){return this.node.getTotalLength?this.node.getTotalLength():void 0},H.getPointAtLength=function(a){return U(this.attr("d"),a)},H.getSubpath=function(b,c){return a.path.getSubpath(this.attr("d"),b,c)},a._.box=d,a.path.findDotsAtSegment=i,a.path.bezierBBox=j,a.path.isPointInsideBBox=k,a.path.isBBoxIntersect=l,a.path.intersection=r,a.path.intersectionNumber=s,a.path.isPointInside=u,a.path.getBBox=v,a.path.get=X,a.path.toRelative=y,a.path.toAbsolute=z,a.path.toCubic=E,a.path.map=F,a.path.toString=e,a.path.clone=f}),d.plugin(function(a){var d=Math.max,e=Math.min,f=function(a){if(this.items=[],this.bindings={},this.length=0,this.type="set",a)for(var b=0,c=a.length;c>b;b++)a[b]&&(this[this.items.length]=this.items[this.items.length]=a[b],this.length++)},g=f.prototype;g.push=function(){for(var a,b,c=0,d=arguments.length;d>c;c++)a=arguments[c],a&&(b=this.items.length,this[b]=this.items[b]=a,this.length++);return this},g.pop=function(){return this.length&&delete this[this.length--],this.items.pop()},g.forEach=function(a,b){for(var c=0,d=this.items.length;d>c;c++)if(a.call(b,this.items[c],c)===!1)return this;return this},g.animate=function(d,e,f,g){"function"!=typeof f||f.length||(g=f,f=c.linear),d instanceof a._.Animation&&(g=d.callback,f=d.easing,e=f.dur,d=d.attr);var h=arguments;if(a.is(d,"array")&&a.is(h[h.length-1],"array"))var i=!0;var j,k=function(){j?this.b=j:j=this.b},l=0,m=g&&function(){l++==this.length&&g.call(this)};return this.forEach(function(a,c){b.once("snap.animcreated."+a.id,k),i?h[c]&&a.animate.apply(a,h[c]):a.animate(d,e,f,m)})},g.remove=function(){for(;this.length;)this.pop().remove();return this},g.bind=function(a,b,c){var d={};if("function"==typeof b)this.bindings[a]=b;else{var e=c||a;this.bindings[a]=function(a){d[e]=a,b.attr(d)}}return this},g.attr=function(a){var b={};for(var c in a)this.bindings[c]?this.bindings[c](a[c]):b[c]=a[c];for(var d=0,e=this.items.length;e>d;d++)this.items[d].attr(b);return this},g.clear=function(){for(;this.length;)this.pop()},g.splice=function(a,b){a=0>a?d(this.length+a,0):a,b=d(0,e(this.length-a,b));var c,g=[],h=[],i=[];for(c=2;c
' . __('Minimal version of PHP required: ', 'noti') . '' . $Noti_minimalRequiredPhpVersion . '' .
+ '
' . __('Your server\'s PHP version: ', 'noti') . '' . phpversion() . '' .
+ '';
+}
+
+
+function Noti_PhpVersionCheck() {
+ global $Noti_minimalRequiredPhpVersion;
+ if (version_compare(phpversion(), $Noti_minimalRequiredPhpVersion) < 0) {
+ add_action('admin_notices', 'Noti_noticePhpVersionWrong');
+ return false;
+ }
+ return true;
+}
+
+
+/**
+ * Initialize internationalization (i18n) for this plugin.
+ * References:
+ * http://codex.wordpress.org/I18n_for_WordPress_Developers
+ * http://www.wdmac.com/how-to-create-a-po-language-translation#more-631
+ * @return void
+ */
+function Noti_i18n_init() {
+ $pluginDir = dirname(plugin_basename(__FILE__));
+ load_plugin_textdomain('noti', false, $pluginDir . '/languages/');
+}
+
+
+//////////////////////////////////
+// Run initialization
+/////////////////////////////////
+
+// First initialize i18n
+Noti_i18n_init();
+
+
+// Next, run the version check.
+// If it is successful, continue with initialization for this plugin
+if (Noti_PhpVersionCheck()) {
+ // Only load and run the init function if we know PHP version can parse it
+ include_once('noti_init.php');
+ Noti_init(__FILE__);
+}
diff --git a/noti/noti_init.php b/noti/noti_init.php
new file mode 100644
index 0000000..765f80a
--- /dev/null
+++ b/noti/noti_init.php
@@ -0,0 +1,53 @@
+isInstalled()) {
+ $aPlugin->install();
+ }
+ else {
+ // Perform any version-upgrade activities prior to activation (e.g. database changes)
+ $aPlugin->upgrade();
+ }
+
+ // Add callbacks to hooks
+ $aPlugin->addActionsAndFilters();
+
+ if (!$file) {
+ $file = __FILE__;
+ }
+ // Register the Plugin Activation Hook
+ register_activation_hook($file, array(&$aPlugin, 'activate'));
+
+
+ // Register the Plugin Deactivation Hook
+ register_deactivation_hook($file, array(&$aPlugin, 'deactivate'));
+}
diff --git a/noti/readme.txt b/noti/readme.txt
new file mode 100644
index 0000000..6360a55
--- /dev/null
+++ b/noti/readme.txt
@@ -0,0 +1,29 @@
+=== Noti ===
+Contributors: Arash
+Donate link:
+Tags:
+License: GPLv3
+License URI: http://www.gnu.org/licenses/gpl-3.0.html
+Requires at least: 3.5
+Tested up to: 3.5
+Stable tag: 0.1
+
+This plugin do ...
+
+== Description ==
+
+This plugin do ...
+
+== Installation ==
+
+
+== Frequently Asked Questions ==
+
+
+== Screenshots ==
+
+
+== Changelog ==
+
+= 0.1 =
+- Initial Revision